package cn.itsource.test;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

// 了解一下多线程开发
public class ZookeeperDistributedLock{
    ZkClient client = new ZkClient("127.0.0.1:2181",
            5000);
    CountDownLatch cdl = new CountDownLatch(1); //不为零阻塞住，不让他往下走  多线程的一个东西
    //父节点路径
    String parent = "";
    //当前节点路径
    String currentPath = "";
    //1 goods
    // lock_goods_id 父节点（持久节点）
    // lock_goods_id_001
    // lock_goods_id_002
    public void lock(String resourceName) {
        parent = "/"+resourceName;
        //判断父节点是否存在，如果不存在要创建一个持久节点
        if (!client.exists(parent)){ //true false
            client.createPersistent(parent,"root");
        }
        //前面的节点都处理完成，自己变成第一个节点才加锁成功。
        if (!tryLock(resourceName)){
            lock(resourceName);
        }
    }

    public void unlock(String resourceName) {
        //自己操作完毕，删除自己，让下一个节点执行。
        System.out.println(currentPath);
        System.out.println(System.currentTimeMillis());
        System.out.println(client.delete(currentPath));
        client.close();
    }

    public boolean tryLock(String resourceName) {
        //创建子节点-临时顺序节点
        if (StringUtils.isEmpty(currentPath)){
            currentPath = client
                    .createEphemeralSequential(parent + "/test", "test"); //test0001
        }
        //如果是第一个节点，就获取到锁了。
        List<String> children = client.getChildren(parent);
        System.out.println(currentPath+"jjj");
        for (String child : children) {
            System.out.println(child);
        }
        Collections.sort(children); //升序排序
        ///goods_1/test0000000003jjj
        //test0000000003   如果是第一个节点，表示获取到锁
        if (currentPath.contains(children.get(0))){
            return true;// 如果是第一个节点  就出去
        }else{
            //如果不是第一个节点，监听前一个节点，要再这儿等待，知道被触发，再次判断是否是第一个节点进行返回就OK
            String str = currentPath.substring(
                    currentPath.lastIndexOf("/")+1);
            System.out.println(str);
            int preIndex = children.indexOf(str)-1;
            String prePath = parent+"/"+children.get(preIndex);
            //监听上一个节点，如果上一个节点被删除，把秒表设置为 0 （cdl.countDown();），那么当前节点取消等待(cdl.await();)重新获取锁
            client.subscribeDataChanges(prePath, new IZkDataListener() {
                @Override
                public void handleDataChange(String dataPath, Object data) throws Exception {

                }
                @Override
                public void handleDataDeleted(String dataPath) throws Exception {
                    //让他-1 变为零
                    cdl.countDown();
                }
            });
            //一直等待，直到自己变成第一个节点
            try {
                cdl.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return false;
        }
    }
}